#include "head.h"

int transFile(int sockfd, cmd_t Cmd)
{
    printf("begin to send!\n");
    train_t train;
    // 先打开文件
    char path[1024] = {0};
    sprintf(path, "%s%s%s", "upload", "/", Cmd.object);
    int fd = open(path, O_RDWR);
    if (fd == -1)
    { // 打开文件失败，发送一节空车箱通知对方
        perror("open");
        bzero(&train, sizeof(train));
        train.length = 0;
        send(sockfd, &train, sizeof(train.length) + train.length, 0);
    }
    // 将文件名发送给对方
    printf("file_name is %s\n", Cmd.object);
    bzero(&train, sizeof(train));
    train.length = strlen(Cmd.object);
    memcpy(train.data, Cmd.object, strlen(Cmd.object));
    send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    // 获取文件长度，并将其装入火车发送
    struct stat statbuf;
    fstat(fd, &statbuf);
    bzero(&train, sizeof(train));
    train.length = sizeof(statbuf.st_size);
    memcpy(train.data, &statbuf.st_size, sizeof(statbuf.st_size));
    send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    // 计算并发送文件md5值
    char md5_str[MD5_STR_LEN + 1] = {0};
    Compute_file_md5(path, md5_str);
    bzero(&train, sizeof(train));
    train.length = strlen(md5_str);
    memcpy(train.data, md5_str, strlen(md5_str));
    send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    // 判断是否需要上传
    int check;
    recvn(sockfd, &check, sizeof(int));
    if (check == 0) // 不需要上传
    {
        return 0;
    }
    // 获得文件已传大小
    off_t exitSize = 0;
    recvn(sockfd, &exitSize, sizeof(exitSize));
    // lseek(fd,exitSize,SEEK_SET);
    // 使用mmap后再传送不需要用到lseek
    off_t totalSize = exitSize;

    char *p = (char *)mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    ERROR_CHECK(p, MAP_FAILED, "mmap");

    if (statbuf.st_size >= 1073741824)
    { // 文件大于1G,直接一次性发送
        send(sockfd, p, statbuf.st_size, MSG_NOSIGNAL);
    }
    else
    { // 文件小于等于1G，先mmap再send
        printf("send with mmap\n");
        while (totalSize < statbuf.st_size)
        {
            if (statbuf.st_size - totalSize > sizeof(train.data))
            {
                train.length = sizeof(train.data);
            }
            else
            {
                train.length = statbuf.st_size - totalSize;
            }
            memcpy(train.data, p + totalSize, train.length);
            totalSize += train.length;
            send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
        }
        train.length = 0;
        send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    }
    close(fd);
    munmap(p, statbuf.st_size);
    return 0;
}